#include <chrono>
#include <exception>
#include <iostream>
#include <sstream>
#include <thread>

namespace Encapsulation {
    class Thread {
    public:
        Thread()
            : running_(false)
            , th_(nullptr){}; // 构造函数
        virtual ~Thread() {   // 析构函数
            if (th_ != NULL) {
                //如果到调用析构函数的时候，调用者还没有调用join则触发detach，
                //此时是一个比较危险的动作，用户必须知道他在做什么
                if (th_->joinable()) {
                    std::cout << "~Thread detach\n";
                    th_->detach();
                }

                delete th_;
                th_ = NULL;
            }
            std::cout << "~Thread()" << std::endl;
        }

        bool start() {
            if (running_) {
                return false;
            }
            try {
                th_ = new std::thread(&Thread::threadEntry, this);
            }
            catch (...) {
                throw "[Thread::start] thread start error";
            }
            return true;
        }
        void stop() {
            running_ = false;
        }
        bool isAlive() const { // 线程是否存活.
            return running_;
        }
        void join() { // 等待当前线程结束, 不能在当前线程上调用
            if (th_->joinable()) {
                th_->join(); // 不是detach才去join
            }
        }
        void detach() { //能在当前线程上调用
            th_->detach();
        }

        std::thread::id id() {
            return th_->get_id();
        }
        std::thread *getThread() {
            return th_;
        }
        static size_t CURRENT_THREADID() {
            // 声明为thread_local的本地变量在线程中是持续存在的，不同于普通临时变量的生命周期，
            // 它具有static变量一样的初始化特征和生命周期，即使它不被声明为static。
            static thread_local size_t threadId = 0;
            if (threadId == 0) {
                std::stringstream ss;
                ss << std::this_thread::get_id();
                threadId = strtol(ss.str().c_str(), nullptr, 0);
            }
            return threadId;
        }

    protected:
        void threadEntry() {
            running_ = true;

            try {
                run(); // 函数运行所在 调用子类的run函数
            }
            catch (std::exception &ex) {
                running_ = false;
                throw ex;
            }
            catch (...) {
                running_ = false;
                throw;
            }
            running_ = false;
        }

        virtual void run() = 0; // 运行
    protected:
        bool         running_; //是否在运行
        std::thread *th_;
    };
} // namespace Encapsulation

class A : public Encapsulation::Thread {
public:
    void run() {
        while (running_) {
            std::cout << "print A, "
                      << "Current threadId: " << Encapsulation::Thread::CURRENT_THREADID() << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(5));
        }
        std::cout << "----- leave A \n";
    }
};
class B : public Encapsulation::Thread {
public:
    void run() {
        while (running_) {
            std::cout << "print B, "
                      << "Current threadId: " << Encapsulation::Thread::CURRENT_THREADID() << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(2));
        }
        std::cout << "----- leave B \n";
    }
};

int main() {
    {
        std::cout << "Current threadId: " << Encapsulation::Thread::CURRENT_THREADID() << std::endl;
        A a;
        a.start();

        B b;
        b.start();

        std::this_thread::sleep_for(std::chrono::seconds(10));

        a.stop();
        a.join();

        b.stop();
        b.join(); // 需要我们自己join
    }
    return 0;
}